/*
 *                    COPYRIGHT NOTICE
 *
 *           This code is copyright protected by Freedom Inc.
 *
 *              2001-2012 All Rights Are Reserved
 */
package com.freedom.oldsong.util;

import java.util.Arrays;

import com.freedom.oldsong.system.dto.PaginationResult;
import com.ibatis.sqlmap.client.SqlMapException;
import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
import com.ibatis.sqlmap.engine.mapping.result.ResultMapping;
import com.ibatis.sqlmap.engine.mapping.sql.stat.StaticSql;
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
import com.ibatis.sqlmap.engine.type.IntegerTypeHandler;

/**
 * @author steven.wang
 *
 */
public final class PaginationUtil {
	
	private PaginationUtil(){
		
	}
	
	public final static String PAGINATION = "pagination_";
	public final static String COUNT = "count_";
	
	/**
	 * @param type
	 * @param paginationResult
	 * @param sql
	 * @return
	 */
	private static String getSqlString(String type, PaginationResult paginationResult, String sql){
		if(PAGINATION.equals(type)){
			return sql.toLowerCase().replaceFirst(
					"select",
					"select  top " + paginationResult.getPageSize()
							+ " * from (select row_number() over(ORDER by " + paginationResult.getSort()
							+ ") as rownumber, ")
					+ "  ) as tb where rownumber>"
					+ ((paginationResult.getCurrentPage() - 1) * paginationResult.getPageSize())
					+ " ORDER BY rownumber";
		}else{
			return "select count(*) as count " + sql.toLowerCase().substring(sql.toLowerCase().indexOf("from"));
		}
		
	}
	
	/**
	 * @param type
	 * @param queryName
	 * @param pagination
	 * @param sqlmap
	 */
	public static void checkStatement(String type, String queryName, PaginationResult pagination, SqlMapClientImpl sqlmap){
		try {
			sqlmap.getMappedStatement(type + queryName);
			if(PaginationUtil.PAGINATION.equals(type)){
				generatePaginationStatement(type, queryName, pagination, sqlmap, true);
			}
		}catch(SqlMapException e){
			generatePaginationStatement(type, queryName, pagination, sqlmap, false);
		}
	}
	
	/**
	 * @param type
	 * @param queryName
	 * @param pagination
	 * @param sqlmap
	 * @param isExisted
	 */
	private static void generatePaginationStatement(String type, String queryName, PaginationResult pagination, SqlMapClientImpl sqlmap, boolean isExisted){
			//SqlMapClientImpl sqlmap = (SqlMapClientImpl) this.getSqlMapClient();
			MappedStatement stmt = sqlmap.getMappedStatement(queryName);
			MappedStatement newstmt =null;
			if(isExisted){
				newstmt = sqlmap.getMappedStatement(type+queryName);
				StaticSql stq = (StaticSql) stmt.getSql();
				String sqlString = getSqlString(type, pagination, stq.getSql(null, null));
				newstmt.setSql(new StaticSql(sqlString));
			}else{
				newstmt = new MappedStatement();
				StaticSql stq = (StaticSql) stmt.getSql();
				String sqlString = getSqlString(type, pagination, stq.getSql(null, null));
				newstmt.setSql(new StaticSql(sqlString));

				newstmt.setParameterClass(stmt.getParameterClass());
				newstmt.setParameterMap(stmt.getParameterMap());
				newstmt.setId(type + stmt.getId());
				newstmt.setFetchSize(stmt.getFetchSize());
				newstmt.setResource(stmt.getResource());
			
				newstmt.setSqlMapClient(stmt.getSqlMapClient());
				newstmt.setResultSetType(stmt.getResultSetType());
				if(PAGINATION.equals(type)){
					newstmt.setResultMap(stmt.getResultMap());
				}else{
					ResultMap rm = new ResultMap(sqlmap.delegate);
					newstmt.setResultMap(rm);
					newstmt.getResultMap().setResultClass(Integer.class);
					ResultMapping resultMapping = new ResultMapping();
					resultMapping.setColumnIndex(1);
					resultMapping.setJavaType(Integer.class);
					resultMapping.setJdbcTypeName("INTEGER");
					resultMapping.setPropertyName("");
					resultMapping.setColumnName("count");
					resultMapping.setTypeHandler(new IntegerTypeHandler()); 
					newstmt.getResultMap().setResultMappingList(Arrays.asList(resultMapping));
				}
				sqlmap.delegate.addMappedStatement(newstmt);
			}
			 
			
		
	}
}
